package GUI;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
import Controlers.InvaderControler;
import Controlers.LifeBarControler;
import Controlers.SoundControler;
import Invaders.Invader;
import Objects.Bullet;
import Objects.Estado;
import Objects.Power;
import Objects.Score;
import Objects.Shooter;
import Util.FilterNumber;

// Classe que implementa o painel do jogo. O painel controla os elementos
// do jogo e a renderização.
public class InvadersPanel extends JPanel implements Runnable,KeyListener, ActionListener {
	
	private static final long serialVersionUID = 1L;
	// Dimensoes da Area do jogo.
	protected static final int largura = 800;
	protected static final int altura = 690;
	protected static final int larguraShooter = largura;
	protected static final int alturaShooter = altura - 90;
	  // Uma thread para controlar a animacao.
	protected Thread animator;         
	protected boolean isPaused = false;
	  // Teremos alguns UFOs passeando na tela.
	protected ArrayList<Invader> invasores;
	protected int NUM_INVASORES = 10;
	  // O shooter e sua direção de movimento.
	protected Shooter shooter;
	protected Estado dir;
	  // Um conjunto de tiros.
	protected ArrayList<Bullet> tiros;
	protected static final int MAX_TIROS = 10;
	  // Uma única bomba com limite de 10 por round.
	protected int numBombas;
	protected static final int NUM_BOMBAS_DISPONIVEL = 100;
	private Timer timer;
	private int time;
	private Score score;
	private LifeBarControler lifeBar;
	private FilterNumber filterNumber;
	private int level;
	private int life;
	private InvaderControler invadersCreator;
	private SoundControler som;  
	private MainFrame frame;
	private MenuPanel menuPanel;
	private Power poder;
	
	// Controlador do SpriteSheet do Background
	private int bgs_y1, bgs_y2;
	private int bgt_y1, bgt_y2;
  
	// Construtor, inicializa estruturas, registra interfaces, etc.  
	public InvadersPanel(MainFrame frame, MenuPanel menuPanel) {
		this.menuPanel = menuPanel;
		this.frame = frame;
		som = new SoundControler();
		som.playBackgroundMusic();
		setBackground(Color.WHITE);
	    timer = new Timer(500,this);
		timer.setCoalesce(true);
		timer.start();
	    time = 63;
	    score = new Score(new Dimension(largura,altura-90));
	    lifeBar = new LifeBarControler();
	    filterNumber = new FilterNumber();
	    level = 1;
	    life = 3;
	    setPreferredSize(new Dimension(largura,altura));
	    requestFocus(); 
	    addKeyListener(this);
	    invasores = new ArrayList<Invader>(NUM_INVASORES);
	    shooter = new Shooter(new Dimension(larguraShooter,alturaShooter));
	    poder = new Power(invasores, shooter, score);
	    shooter.setEstado(Estado.DOWN);
	    tiros = new ArrayList<Bullet>(MAX_TIROS);
	    numBombas = NUM_BOMBAS_DISPONIVEL;
	    invadersCreator = new InvaderControler(invasores, larguraShooter, alturaShooter);
	    bgs_y1 = 0;
	    bgs_y2 = 600;
	    bgt_y1 = 600;
	    bgt_y2 = 1200;
    }
  
	// Avisa que agora temos a interface em um container parente. 
	public void addNotify() { 
	    super.addNotify();  
	    startGame();        
    }

	// Iniciamos o jogo (e a thread de controle)
	private void startGame() { 
	    if (animator == null) {
	      animator = new Thread(this);
	      animator.start();
	    }
    } 
	
	// Atualizamos os elementos do jogo.
	private synchronized void gameUpdate() {
	    if (!isPaused) {
	    	if(life == 0) {
				  goGameOver();
	    	}
	    	if(level == 8) {
	    		goCongratulations();
	    	}
	    	score.updateScore();
	    	shooter.move(shooter.getEstado());
	    	// Movemos os sprites.
			for(Invader i:invasores) {
				i.move();
			}
			//shooter.move(dir);
			for(Bullet b:tiros) {
				b.move();
			}
			// Temos balas desativadas?
			// Não usar [for(Bullet b:tiros) { if (!b.estáAtivo()) tiros.remove(b); }]!
			Iterator<Bullet> it = tiros.iterator();
			while (it.hasNext()) {
			  if (!(it.next()).estaAtivo()) {
				  it.remove();
			  }
			}
			// Temos invasores desativados?
			Iterator<Invader> ii = invasores.iterator();
			while (ii.hasNext()) {
			  if (!(ii.next()).estaAtivo()) {
				  ii.remove();
			  }
			}
			// Temos colisões com balas?
			try {
				for(Bullet b:tiros) {
					for(Invader i:invasores) {
						if (b.acertouEm(i)) {
							//i.desativa();
							score.addScore(i.getScore());
						}
					}
				}
			}
			catch(ConcurrentModificationException e) {}
			// Temos colisao com o shooter
			for(Invader i:invasores) {
				if (i.acertouEm(shooter)) {
					shooter.perdeVida(i.causaDano());
					shooter.zeraContPosHit();
					if(shooter.estaSemLife()) {
						shooter = new Shooter(new Dimension(larguraShooter,alturaShooter));
						poder.setShooter(shooter);
						life--;
						shooter.move(shooter.getEstado());
					}
			    }
			}
			
			poder.exucutar();

	    }
	}
  
	// Laço principal do jogo.  
	public void run() {
	    while(true) {	
	    	gameUpdate();
	    	repaint();
	    	try {
	    		Thread.sleep(10);
		    }
	    	catch (InterruptedException e) {
	    		e.printStackTrace();
		    }
    	}
    }
	
	// Desenhamos o componente (e seus elementos)
	protected synchronized void paintComponent(Graphics g) {
	    super.paintComponent(g);
	    // Bg com SpriteSheet
	    Image icon = new ImageIcon(getClass().getResource("/Sprites/background.png")).getImage();;
	    if(bgs_y1 < 3000) {
		    g.drawImage(icon,       0,0,800,600,          0,bgs_y1, 800, bgs_y2,            null);
		    bgs_y1+=3;
		    bgs_y2+=3;
	    }
	    else {
		    if(bgs_y1 >= 3000 && bgs_y1 <= 3600) {
		    	g.drawImage(icon, 0,0,800,600,     0,bgs_y1, 800, bgs_y2, null);
		    	g.drawImage(icon, 0,bgt_y1,800,bgt_y2,     0,0, 800, 600, null);
		    	bgt_y1-=3;
		    	bgt_y2-=3;
		    	bgs_y1+=3;
			    bgs_y2+=3; 
		    }
		    else {
			    bgt_y1 = 600;
			    bgt_y2 = 1200;
			    bgs_y1 = 0;
			    bgs_y2 = 600;
		    }
	    }	    
	    for(Invader i:invasores) {
	    	i.draw(g);
	    }
	    shooter.draw(g);
	    for(Bullet b:tiros) {
	    	b.draw(g);
	    }
	    
	    // GELO BG
	    g.fillRect(0, 595, 800, 5);
	    g.drawImage(new ImageIcon(getClass().getResource("/Sprites/barrafundo.png")).getImage(), 0, 600, null);
	    // LIFE BAR
	    lifeBar.draw(g, shooter);
	    // LIFE
	    g.drawImage(new ImageIcon(getClass().getResource("/Sprites/Life.png")).getImage(), 40, 650, null);
	    g.drawImage(filterNumber.setImage(life, 1), 170, 650, null);
	    // TIME
	    g.drawImage(filterNumber.setImage(time/10, 2), 340, 600, null);
	    g.drawImage(filterNumber.setImage(time%10, 2), 370, 600, null);
	    g.drawImage(new ImageIcon(getClass().getResource("/Sprites/Time.png")).getImage(), 320, 650, null);
	    // SCORE
	    g.drawImage(new ImageIcon(getClass().getResource("/Sprites/Score.png")).getImage(), largura-350, 605, null);
	    score.draw(g);
	    // Level
	    g.drawImage(new ImageIcon(getClass().getResource("/Sprites/Level.png")).getImage(), largura-250, 650, null);
	    g.drawImage(filterNumber.setImage(level, 1), largura-110, 650, null);
	    
	    poder.draw(g);
    }

	// Processamos teclas pressionadas durante o jogo.
	public void keyPressed(KeyEvent e) {
	    int keyCode = e.getKeyCode();
	    if (keyCode == KeyEvent.VK_P) {
	    	isPaused = !isPaused;
	    }
	    if (isPaused) {
	    	return;
	    }
	    if (keyCode == KeyEvent.VK_LEFT) {
	    	//shooter.move(Estado.LEFT); 
	    	shooter.setEstado(Estado.LEFT);

	    }
	    else {
	    	if (keyCode == KeyEvent.VK_RIGHT) {
	    		//shooter.move(Estado.RIGHT); 
	    		shooter.setEstado(Estado.RIGHT);
	    	}
	    	else {
	    		if (keyCode == KeyEvent.VK_UP) {
		    		//shooter.move(Estado.UP); 
		    		shooter.setEstado(Estado.UP);

		    	}
	    		else {
	    			if (keyCode == KeyEvent.VK_DOWN) {
				    	//shooter.move(Estado.DOWN);
				    	shooter.setEstado(Estado.DOWN);

	    			}
	    		}
	    	}
	    }	    
    }

	// Estes métodos servem para satisfazer a interface KeyListener
	public void keyReleased(KeyEvent e) { 
		  int keyCode = e.getKeyCode();
		  if (keyCode == KeyEvent.VK_SPACE) {
			  if(shooter.getEstaAtivo()) {
				  if (tiros.size() < MAX_TIROS) {// podemos adicionar mais tiros
					  shooter.zeraContPosShoot();
					  //som.playshootdMusic();
					  tiros.add(new Bullet(getPreferredSize(),shooter.getX()+shooter.getWidth()/2,shooter.getY()-shooter.getHeight()/2,Estado.UP));
				  }
			  }
	      }
		  else {
			  if(keyCode == KeyEvent.VK_ENTER) {
				  poder.ativar();
			  }
		  }
	}

	public void keyTyped(KeyEvent e) { }

	@Override
	public synchronized void actionPerformed(ActionEvent e) {
		time--;
		poder.encherMana();
		invadersCreator.criaInvader(level, time);
		if(time == -1) {
			time = 63;
			level++;
		}
	}
 	
	public void goCongratulations() {
		this.setVisible(false);
		CongratulationsPanel congratulationsPainel = new CongratulationsPanel(frame, score);
		frame.add(congratulationsPainel);
		congratulationsPainel.requestFocus();
	}
	
	public void goGameOver() {
		
		if(level < 8) {
			animator = null;
			timer.stop();
			this.setVisible(false);
			GameOverPanel gameOverPanel = new GameOverPanel(frame, score, menuPanel);
			frame.setGameOverPanel(gameOverPanel);
			frame.add(gameOverPanel);
			gameOverPanel.requestFocus();
		}
	}
 }



